
#include "Shader.h"
#include "Core/Log.h"
#include "RendererAPI.h"
#include "Platform/OpenGL/OpenGLShader.h"
#include "Renderer.h"

namespace Hazel {
//    Shader::Shader(const std::string &vertexSrc, const std::string &fragmentSrc) {
//        // Create an empty vertex shader handle  创建着色器
//        GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
//
//        // Send the vertex shader source code to GL
//        // Note that std::string's .c_str is NULL character terminated.
//        //reference to https://www.khronos.org/opengl/wiki/Shader_Compilation#Example
//        const GLchar* source = vertexSrc.c_str();
//        glShaderSource(vertexShader, 1, &source, 0);
//
//        // Compile the vertex shader
//        glCompileShader(vertexShader);
//
//        GLint isCompiled = 0;
//        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
//        // 判断着色器是否编译成功
//        if (isCompiled == GL_FALSE)
//        {
//            GLint maxLength = 0;
//            glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
//
//            // The maxLength includes the NULL character
//            std::vector<GLchar> infoLog(maxLength);
//            glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
//
//            // We don't need the shader anymore.
//            glDeleteShader(vertexShader);
//
//            HZ_CORE_ERROR("{0}", infoLog.data());
//            HZ_CORE_ASSERT(false, "Vertex shader compilation failure!");
//            return;
//        }
//
//        // Create an empty fragment shader handle 片段着色器
//        GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//
//        // Send the fragment shader source code to GL
//        // Note that std::string's .c_str is NULL character terminated. 重用源变量
//        source = fragmentSrc.c_str();
//        glShaderSource(fragmentShader, 1, &source, 0);
//
//        // Compile the fragment shader
//        glCompileShader(fragmentShader);
//
//        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
//        if (isCompiled == GL_FALSE)
//        {
//            GLint maxLength = 0;
//            glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
//
//            // The maxLength includes the NULL character
//            std::vector<GLchar> infoLog(maxLength);
//            glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
//
//            // We don't need the shader anymore.
//            glDeleteShader(fragmentShader);
//            // Either of them. Don't leak shaders.
//            glDeleteShader(vertexShader);
//
//            HZ_CORE_ERROR("{0}", infoLog.data());
//            HZ_CORE_ASSERT(false, "Fragment shader compilation failure!");
//            return;
//        }
//
//        // Vertex and fragment shaders are successfully compiled.
//        // Now time to link them together into a program.
//        // Get a program object.  创建程序
//        m_RendererID = glCreateProgram();
//        GLuint program = m_RendererID;
//
//        // Attach our shaders to our program  把程序附加着色器
//        glAttachShader(program, vertexShader);
//        glAttachShader(program, fragmentShader);
//
//        // Link our program 程序链接着色器
//        glLinkProgram(program);
//
//        // Note the different functions here: glGetProgram* instead of glGetShader*.
//        GLint isLinked = 0;
//        glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
//        // 判断是否链接成功
//        if (isLinked == GL_FALSE)
//        {
//            GLint maxLength = 0;
//            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
//
//            // The maxLength includes the NULL character
//            std::vector<GLchar> infoLog(maxLength);
//            glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
//
//            // We don't need the program anymore.
//            glDeleteProgram(program);
//            // Don't leak shaders either.
//            glDeleteShader(vertexShader);
//            glDeleteShader(fragmentShader);
//
//            HZ_CORE_ERROR("{0}", infoLog.data());
//            HZ_CORE_ASSERT(false, "Shader link failure!");
//            return;
//        }
//
//        // Always detach shaders after a successful link.
//        glDetachShader(program, vertexShader);
//        glDetachShader(program, fragmentShader);
//    }
//
////    Shader::~Shader() {
////        glDeleteProgram(m_RendererID);
////    }
//
//    void Shader::Bind() const {
//        // 使用or激活
//        glUseProgram(m_RendererID);
//    }
//
//    void Shader::Unbind() const {
//        glUseProgram(0);
//    }

//    void Shader::UploadUniformMat4(const std::string &name, const glm::mat4 &matrix) {
//        GLint location = glGetUniformLocation(m_RendererID, name.c_str());
//        glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
//    }

//    Shader *Shader::Create(const std::string &vertexSrc, const std::string &fragmentSrc) {
    Ref<Shader> Shader::Create(const std::string& filePath) {
        switch (Renderer::GetAPI()) {
            case RendererAPI::API::None:
                HZ_CORE_ASSERT(false, "RendererAPI::None is currently not supported!");
                return nullptr;
            case RendererAPI::API::OpenGL:
//                return new OpenGLShader(vertexSrc, fragmentSrc);
                return CreateRef<OpenGLShader>(filePath);
        }

        HZ_CORE_ASSERT(false, "Unknow RendererAPI::API!");
        return nullptr;
    }
    Ref<Shader> Shader::Create(const std::string& name, const std::string &vertexSrc, const std::string &fragmentSrc) {
        switch (Renderer::GetAPI()) {
            case RendererAPI::API::None:
            HZ_CORE_ASSERT(false, "RendererAPI::None is currently not supported!");
                return nullptr;
            case RendererAPI::API::OpenGL:
                return CreateRef<OpenGLShader>(name, vertexSrc, fragmentSrc);
        }
        HZ_CORE_ASSERT(false, "Unknown RendererAPI!");
        return nullptr;
    }

    void ShaderLibrary::Add(const std::string &name, const Ref<Shader> &shader) {
        HZ_CORE_ASSERT(!Exists(name), "Shader already exists!");
        m_Shaders[name] = shader;
    }

    void ShaderLibrary::Add(const Ref<Shader> &shader) {
        auto& name = shader->GetName();
        HZ_CORE_ASSERT(!Exists(name), "Shader already exists!");
        Add(name, shader);
    }

    Ref<Shader> ShaderLibrary::Load(const std::string &filePath) {
        auto shader = Shader::Create(filePath);
        Add(shader);
        return shader;
    }

    Ref<Shader> ShaderLibrary::Load(const std::string &name, const std::string &filePath) {
        auto shader = Shader::Create(filePath);
        Add(shader);
        return shader;
    }

    Ref<Shader> ShaderLibrary::Get(const std::string &name) const {
        HZ_CORE_ASSERT(Exists(name), "Share not found!");
        return m_Shaders.at(name);
    }

    bool ShaderLibrary::Exists(const std::string &name) const {
        return m_Shaders.find(name) != m_Shaders.end();
    }
}
